package com.goldenautumn.prefabricate.business.user

import android.app.Application
import androidx.annotation.NonNull
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.JsonUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.SPUtils
import com.blankj.utilcode.util.TimeUtils
import com.blankj.utilcode.util.ToastUtils
import com.blankj.utilcode.util.Utils
import com.github.gzuliyujiang.wheelpicker.entity.CityEntity
import com.github.gzuliyujiang.wheelpicker.entity.CountyEntity
import com.github.gzuliyujiang.wheelpicker.entity.ProvinceEntity
import com.goldenautumn.prefabricate.R
import com.goldenautumn.prefabricate.activity.account.LoginActivity
import com.goldenautumn.prefabricate.activity.account.PhoneLoginActivity
import com.goldenautumn.prefabricate.business.entity.AddressCreateParams
import com.goldenautumn.prefabricate.business.entity.LanguageInfo
import com.goldenautumn.prefabricate.business.entity.LanguageInfoVo
import com.goldenautumn.prefabricate.business.entity.LoginParams
import com.goldenautumn.prefabricate.business.entity.PaymentMethodVo
import com.goldenautumn.prefabricate.utils.Constants.IS_LOGIN
import com.goldenautumn.prefabricate.utils.Constants.LOGIN_TOKEN
import com.goldenautumn.prefabricate.utils.Constants.USER_ID
import com.goldenautumn.prefabricate.utils.onCenterToast
import com.goldenautumn.prefabricate.wxapi.WXEntryActivity
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import org.json.JSONObject
import qncx.external.common.Global
import qncx.external.common.base.BaseViewModel
import qncx.external.common.room.RoomSql
import qncx.external.common.room.table.UserInfo
import java.io.File
import java.util.Locale

class UserViewModel(@NonNull application: Application) : BaseViewModel(application) {

    private val mRepository: UserRepositoryImpl = UserRepositoryImpl()

    val loginRequests: Channel<LoginUiState> = Channel(Channel.UNLIMITED)

    val loading: Channel<LoadingUiState> = Channel(Channel.UNLIMITED)

    val user: Channel<UserInfoUiState> = Channel(Channel.UNLIMITED)

    val addressUiState: Channel<UserAddressUiState> = Channel(Channel.UNLIMITED)

    fun onPhoneLogin(userName: String, pwd: String) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                loginRequests.trySend(LoginUiState.LoginFail(it ?: Utils.getApp().getString(R.string.login_fail)))
            }, requestCall = {
                var userInfo = mRepository.onLogin(LoginParams(userName, pwd))
                SPUtils.getInstance().put(IS_LOGIN, true)
                SPUtils.getInstance().put(LOGIN_TOKEN, userInfo.token)
                SPUtils.getInstance().put(USER_ID, userInfo.user_id)
                mRepository.getUserInfo()
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                info?.userInfo?.let { info ->
                    var userInfo = UserInfo()
                    userInfo.userId = info.user_id
                    userInfo.avatarUrl = info.avatarUrl
                    userInfo.phone = userName
                    userInfo.nickName = info.nickName
                    userInfo.gender = info.gender
                    userInfo.phone = info.mobile
                    userInfo.wechat = info.open_id
                    userInfo.bindWechat = info.is_bind_wx
                    userInfo.bindPhone = info.is_bind_mobile
                    userInfo.address =
                        if (info.address_default == null) null else GsonUtils.toJson(info.address_default)
                    convertToUserInfo(userInfo)
                    loginRequests.trySend(LoginUiState.LoginSuccess(userInfo))
                }

            }

//           flow {
//                val result = mRepository.onLogin(LoginParams(userName, pwd))
//                LogUtils.d("请求结果=${result}")
//                if(result != null) convertToUserInfo(result)
//                SPUtils.getInstance().put(IS_LOGIN,true)
//                SPUtils.getInstance().put(LOGIN_TOKEN,result.token)
//                SPUtils.getInstance().put(USER_ID,result.userId ?: 0)
//                emit(result)
//            }.onStart {//在上游流启动之前被调用。
//                LogUtils.d("------onStart--------${ThreadUtils.isMainThread()}")
//            }.onEach {//在上游流的每个值被下游发出之前调用。
//                LogUtils.d("------onEach-------${ThreadUtils.isMainThread()}")
//            }.onCompletion {//在流程完成或取消后调用，并将取消异常或失败作为操作的原因参数传递
////               loginRequests.trySend(LoginUiState.LoginFail(it?.message ?: "登录失败"))
//                LogUtils.d("---------onCompletion--------${it}")
//            }.flowOn(Dispatchers.IO).catch { cause ->
//               loginRequests.trySend(LoginUiState.LoginFail(cause.message ?: "登录失败"))
//               LogUtils.d("---------catch--------${cause}")
//            }.collect {
//               loginRequests.trySend(LoginUiState.LoginSuccess(it))
//            }
        }
    }

    fun onWeChatLogin(code: String) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                ActivityUtils.finishActivity(WXEntryActivity::class.java)
                ToastUtils.showLong(it ?: "登录失败")
            }, requestCall = {
                var userInfo = mRepository.onWeChatLogin(code)
                SPUtils.getInstance().put(IS_LOGIN, true)
                SPUtils.getInstance().put(LOGIN_TOKEN, userInfo.token)
                SPUtils.getInstance().put(USER_ID, userInfo.user_id)
                mRepository.getUserInfo()
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                info?.userInfo?.let { info ->
                    var userInfo = UserInfo()
                    userInfo.userId = info.user_id
                    userInfo.avatarUrl = info.avatarUrl
                    userInfo.phone = code
                    userInfo.nickName = info.nickName
                    userInfo.gender = info.gender
                    userInfo.phone = info.mobile
                    userInfo.wechat = info.open_id
                    userInfo.bindWechat = info.is_bind_wx
                    userInfo.bindPhone = info.is_bind_mobile
                    userInfo.address =
                        if (info.address_default == null) null else GsonUtils.toJson(info.address_default)
                    convertToUserInfo(userInfo)
                    ActivityUtils.finishActivity(WXEntryActivity::class.java)
                    ActivityUtils.finishActivity(LoginActivity::class.java)
                }

            }
        }
    }

    fun getCode(phone: String, type: String? = "20") {
        viewModelScope.launch {
            launchFlow(errorCall = {
                loginRequests.trySend(LoginUiState.CodeResult(it ?: "获取失败"))
            }, requestCall = {
                mRepository.getCode(phone, type)
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { _ ->
                loginRequests.trySend(LoginUiState.CodeResult(null))
            }
        }
    }

    fun getUserInfo() {
        viewModelScope.launch {
            launchFlow(errorCall = {
                LogUtils.d("获取用户信息失败=${it}")
            }, requestCall = {
                var userInfo = RoomSql.get()?.userInfoDao?.activeUserInfo
                userInfo?.let { user.trySend(UserInfoUiState.UserInfo(it)) }
                mRepository.getUserInfo()
            }) { info ->
                info?.userInfo?.let {
                    var userInfo = UserInfo()
                    userInfo.userId = it.user_id
                    userInfo.avatarUrl = it.avatarUrl
                    userInfo.nickName = it.nickName
                    userInfo.gender = it.gender
                    userInfo.phone = it.mobile
                    userInfo.wechat = it.open_id
                    userInfo.bindWechat = it.is_bind_wx
                    userInfo.bindPhone = it.is_bind_mobile
                    userInfo.address =
                        if (it.address_default == null) null else GsonUtils.toJson(it.address_default)
                    convertToUserInfo(userInfo)
                    user.trySend(UserInfoUiState.UserInfo(userInfo))
                }
                info?.orderCount?.let { user.trySend(UserInfoUiState.OrderCount(it)) }
//                info?.menus?.let { user.trySend(UserInfoUiState.UserMenu(it)) }
            }
        }
    }

    private fun convertToUserInfo(it: UserInfo): UserInfo {
        var userInfoDao = RoomSql.get()?.userInfoDao
        var userInfo = it
        var loginInfo = userInfoDao?.activeUserInfo
        if (loginInfo != null && loginInfo?.userId != userInfo.id) {
            loginInfo.active = false
            userInfoDao?.updateUserInfo(loginInfo)
        }
        if (loginInfo?.userId == userInfo.userId) { //是当前登录用户保存数据
            userInfo?.active = true
            userInfo.userId = it.userId
            userInfo.id = loginInfo?.id
            var ii = userInfoDao?.updateUserInfo(userInfo)
        } else {
            userInfo.active = true
            userInfo.userId = it.userId
            userInfo.id = null
            var ii = userInfoDao?.insertUserInfo(userInfo)
        }
        return userInfo
    }

    fun getRegionTree() {
        viewModelScope.launch {
            launchFlow(errorCall = {
                LogUtils.d("获取地址信息失败=${it}")
            }, requestCall = {
                mRepository.getRegionTree()
            }) { info ->
                var data: MutableList<ProvinceEntity> = ArrayList()
                info.forEach {
                    var provinceEntity = ProvinceEntity()
                    provinceEntity.name = it.name
                    provinceEntity.code = "${it.id}"
                    var citys: MutableList<CityEntity> = ArrayList()
                    it.city?.forEach { city ->
                        var cityEntity = CityEntity()
                        cityEntity.name = city.name
                        cityEntity.code = "${city.id}"
                        var countys: MutableList<CountyEntity> = ArrayList()
                        city.region?.forEach { county ->
                            var countyEntity = CountyEntity()
                            countyEntity.name = county.name
                            countyEntity.code = "${county.id}"
                            countys.add(countyEntity)
                        }
                        cityEntity.countyList = countys
                        citys.add(cityEntity)
                    }
                    provinceEntity.cityList = citys
                    data.add(provinceEntity)
                }
                addressUiState.trySend(UserAddressUiState.AddressTree(data))
            }
        }
    }

    fun getAddressList() {
        viewModelScope.launch {
            launchFlow(errorCall = {
                LogUtils.d("获取地址信息失败=${it}")
            }, requestCall = {
                mRepository.getAddressList()
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                if (info?.default_id != 0) {
                    info.list?.forEach {
                        it.isDefault = it.address_id == info?.default_id
                    }
                }
                info.list?.let { addressUiState.trySend(UserAddressUiState.AddressList(it)) }
            }
        }
    }

    fun onCreateAddress(params: AddressCreateParams) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                addressUiState.trySend(UserAddressUiState.AddressAction(false, it))
            }, requestCall = {
                mRepository.createAddress(params)
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                addressUiState.trySend(UserAddressUiState.AddressAction(true))
            }
        }
    }

    fun onUpdateAddress(params: AddressCreateParams) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                addressUiState.trySend(UserAddressUiState.AddressAction(false, it))
            }, requestCall = {
                mRepository.updateAddress(params)
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                addressUiState.trySend(UserAddressUiState.AddressAction(true))
            }
        }
    }

    fun onDeleteAddress(params: String) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                addressUiState.trySend(UserAddressUiState.AddressAction(false, it))
            }, requestCall = {
                mRepository.deleteAddress(params)
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                addressUiState.trySend(UserAddressUiState.AddressAction(true))
            }
        }
    }

    fun onDefaultAddress(params: String) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                addressUiState.trySend(UserAddressUiState.AddressAction(false, it))
            }, requestCall = {
                mRepository.defaultAddress(params)
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                addressUiState.trySend(UserAddressUiState.AddressAction(true))
            }
        }
    }

    fun onAddressDetails(params: String) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                addressUiState.trySend(UserAddressUiState.AddressAction(false, it))
            }, requestCall = {
                mRepository.addressDetails(params)
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                info?.detail?.let { addressUiState.trySend(UserAddressUiState.AddressDetails(it)) }
            }
        }
    }

    fun onPayType() {
        viewModelScope.launch {
            launchFlow(errorCall = {}, requestCall = {
                mRepository.onPayType()
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                var methods = ArrayList<PaymentMethodVo>()

                val type = object : TypeToken<Map<String, Map<String, Any>>>() {}.type
                val data: Map<String, Map<String, Any>> = Gson().fromJson(info.toString(), type)
                val payment10 = data["10"]
                val payment20 = data["20"]
                if (payment10 != null) {
                    methods.add(
                        PaymentMethodVo(
                            "${payment10?.get("value")}",
                            R.mipmap.ic_pay_balance,
                            "${payment10?.get("name")}"
                        )
                    )
                }
                if (payment20 != null) {
                    methods.add(
                        PaymentMethodVo(
                            "${payment20?.get("value")}",
                            R.mipmap.ic_payment_method_wechat,
                            "${payment20?.get("name")}"
                        )
                    )
                }

                addressUiState.trySend(UserAddressUiState.PaymentType(methods))
            }
        }
    }

    fun updateUserInfo(niceName: String? = null, img: String? = null) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                user.trySend(
                    UserInfoUiState.UserUpdate(
                        false,
                        it ?: Utils.getApp().getString(R.string.update_failed)
                    )
                )
            }, requestCall = {
                img?.let {
                    var file = File(img)
                    val body: RequestBody =
                        RequestBody.create("image/jpg".toMediaTypeOrNull(), file)
                    val part = MultipartBody.Part.createFormData(
                        "iFile",
                        "${TimeUtils.getNowMills()}.png",
                        body
                    )
                    var upResult = mRepository.updateImage(part)
                    mRepository.updateInfo(avatar = upResult.file_path)
                }
                niceName?.let {
                    mRepository.updateInfo(nickname = niceName)
                }
                getUserInfo()
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { _ ->
                user.trySend(UserInfoUiState.UserUpdate(true))
            }
        }
    }

    fun bindPone(phone: String, code: String) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                user.trySend(
                    UserInfoUiState.UserUpdate(
                        false,
                        it ?: Utils.getApp().getString(R.string.bind_failed)
                    )
                )
            }, requestCall = {
                mRepository.bindPhone(phone, code)
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { _ ->
                user.trySend(UserInfoUiState.UserUpdate(true))
            }
        }
    }

    fun bindWechat(code: String) {
        viewModelScope.launch {
            launchFlow(errorCall = {
                ActivityUtils.finishActivity(WXEntryActivity::class.java)
                onCenterToast(it ?: Utils.getApp().getString(R.string.bind_failed))
            }, requestCall = {
                var result = mRepository.bindWechat(code)
                SPUtils.getInstance().put(LOGIN_TOKEN, result.token)
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { _ ->
                ActivityUtils.finishActivity(WXEntryActivity::class.java)
                onCenterToast(Utils.getApp().getString(R.string.bind_success))
                user.trySend(UserInfoUiState.UserUpdate(true))
            }
        }
    }

    fun getLanguage() {
        viewModelScope.launch {
            launchFlow(errorCall = {}, requestCall = {
                mRepository.getLanguage()
            }, {
                loading.trySend(LoadingUiState.LoadingUI(it))
            }) { info ->
                var language: MutableList<LanguageInfoVo> = ArrayList()
                info.forEach {
                    language.add(languageFormat(it))
                }
                user.trySend(UserInfoUiState.LanguageList(language))
            }
        }
    }

    fun languageFormat(language: LanguageInfo): LanguageInfoVo {
        when (language.language) {
            "zh-cn" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale.SIMPLIFIED_CHINESE,
                    "${language.language}"
                )
            }
            "zh-tw" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale.TRADITIONAL_CHINESE,
                    "${language.language}"
                )
            }
            "ja" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale.JAPAN,
                    "${language.language}"
                )
            }
            "es" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale("es", "ES"),
                    "${language.language}"
                )
            }
            "fr" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale.FRANCE,
                    "${language.language}"
                )
            }
            "de" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale.GERMANY,
                    "${language.language}"
                )
            }
            "ru" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale("ru", "RU"),
                    "${language.language}"
                )
            }
            "uk" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale.UK,
                    "${language.language}"
                )
            }
            "pt" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale("pt", "PT"),
                    "${language.language}"
                )
            }
            "it" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale.ITALY,
                    "${language.language}"
                )
            }
            "ko" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale.KOREA,
                    "${language.language}"
                )
            }
            "tr" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale("tr", "TR"),
                    "${language.language}"
                )
            }
            "nl" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale("nl", "NL"),
                    "${language.language}"
                )
            }
            "ar" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale("ar", "EG"),
                    "${language.language}"
                )
            }
            "th" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale("th", "TH"),
                    "${language.language}"
                )
            }
            "hi" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale("hi"),
                    "${language.language}"
                )
            }
            "id" -> {
                return LanguageInfoVo(
                    "${language.language_content}",
                    "${language.language_alias}",
                    Locale("in", "ID"),
                    "${language.language}"
                )
            }
            else -> return LanguageInfoVo(
                "${language.language_content}",
                "${language.language_alias}",
                Locale.ENGLISH,
                "${language.language}"
            )
        }

    }


}